package com.sas.controller;

import com.sas.common.Result;
import com.sas.dto.RoomView;
import com.sas.entity.Room;
import com.sas.repository.RoomRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;

@RestController
@RequestMapping("/rooms")
@Validated
public class RoomController {

    private static final Logger log = LoggerFactory.getLogger(RoomController.class);

    @Autowired
    private RoomRepository roomRepository;

    /**
     * 房间列表（分页 + 可选筛选）
     */
    @GetMapping
    public Result<Object> getRooms(
            @RequestParam(defaultValue = "0") Integer page,
            @RequestParam(defaultValue = "10") Integer size,
            @RequestParam(required = false) String roomNumber,
            @RequestParam(required = false) String type,
            @RequestParam(required = false) Integer floor,
            @RequestParam(required = false) String status
    ) {
        log.info("查询房间列表 page={}, size={}, roomNumber={}, type={}, floor={}, status={}", page, size, roomNumber, type, floor, status);
        try {
            PageRequest pageable = PageRequest.of(page, size);
            List<Room> list;

            if (roomNumber != null && !roomNumber.trim().isEmpty()) {
                Optional<Room> opt = roomRepository.findByRoomNumber(roomNumber.trim());
                list = opt.map(Collections::singletonList).orElseGet(ArrayList::new);
            } else if (type != null && !type.trim().isEmpty() && status != null && !status.trim().isEmpty()) {
                Integer t = parseType(type);
                Integer s = parseStatus(status);
                list = (t == null || s == null) ? new ArrayList<>() : roomRepository.findByRoomTypeAndStatus(t, s);
            } else if (type != null && !type.trim().isEmpty()) {
                Integer t = parseType(type);
                list = t == null ? new ArrayList<>() : roomRepository.findByRoomType(t);
            } else if (floor != null && status != null && !status.trim().isEmpty()) {
                Integer s = parseStatus(status);
                list = s == null ? new ArrayList<>() : roomRepository.findByFloorAndStatus(floor, s);
            } else if (status != null && !status.trim().isEmpty()) {
                Integer s = parseStatus(status);
                list = s == null ? new ArrayList<>() : roomRepository.findByStatus(s);
            } else {
                Page<Room> pageData = roomRepository.findAll(pageable);
                List<RoomView> views = toViews(pageData.getContent());
                Map<String, Object> pagePayload = new HashMap<>();
                pagePayload.put("content", views);
                pagePayload.put("totalElements", pageData.getTotalElements());
                Map<String, Object> wrapper = new HashMap<>();
                wrapper.put("data", pagePayload);
                return Result.success(wrapper);
            }

            // 手动分页封装
            int start = Math.min((int) pageable.getOffset(), list.size());
            int end = Math.min(start + pageable.getPageSize(), list.size());
            List<RoomView> views = toViews(list.subList(start, end));
            Map<String, Object> pagePayload = new HashMap<>();
            pagePayload.put("content", views);
            pagePayload.put("totalElements", list.size());
            Map<String, Object> wrapper = new HashMap<>();
            wrapper.put("data", pagePayload);
            return Result.success(wrapper);
        } catch (Exception e) {
            log.error("查询房间列表失败", e);
            return Result.error("查询房间列表失败: " + e.getMessage());
        }
    }

    /** 根据ID获取房间详情 */
    @GetMapping("/{id}")
    public Result<RoomView> getRoomById(@PathVariable Long id) {
        log.info("查询房间详情，ID: {}", id);
        Optional<Room> opt = roomRepository.findById(id);
        return opt.map(r -> Result.success(toView(r))).orElseGet(() -> Result.notFound("房间不存在"));
    }

    /** 创建房间 */
    @PostMapping
    public Result<RoomView> createRoom(@RequestBody Map<String, Object> body) {
        try {
            Room r = new Room();
            applyBody(r, body);
            Room saved = roomRepository.save(r);
            return Result.success(toView(saved));
        } catch (Exception e) {
            log.error("创建房间失败", e);
            return Result.error("创建房间失败: " + e.getMessage());
        }
    }

    /** 更新房间 */
    @PutMapping("/{id}")
    public Result<RoomView> updateRoom(@PathVariable Long id, @RequestBody Map<String, Object> body) {
        try {
            Optional<Room> opt = roomRepository.findById(id);
            if (!opt.isPresent()) return Result.notFound("房间不存在");
            Room r = opt.get();
            applyBody(r, body);
            Room saved = roomRepository.save(r);
            return Result.success(toView(saved));
        } catch (Exception e) {
            log.error("更新房间失败", e);
            return Result.error("更新房间失败: " + e.getMessage());
        }
    }

    /** 删除房间 */
    @DeleteMapping("/{id}")
    public Result<Void> deleteRoom(@PathVariable Long id) {
        try {
            roomRepository.deleteById(id);
            return Result.success();
        } catch (Exception e) {
            log.error("删除房间失败", e);
            return Result.error("删除房间失败: " + e.getMessage());
        }
    }

    /** 批量删除房间 */
    @DeleteMapping("/batch")
    public Result<Void> deleteRooms(@RequestBody Map<String, List<Long>> body) {
        try {
            List<Long> ids = body.get("ids");
            if (ids == null) return Result.badRequest("缺少ids字段");
            roomRepository.deleteAllById(ids);
            return Result.success();
        } catch (Exception e) {
            log.error("批量删除房间失败", e);
            return Result.error("批量删除房间失败: " + e.getMessage());
        }
    }

    /** 根据房间号 */
    @GetMapping("/number/{roomNumber}")
    public Result<List<RoomView>> getRoomByNumberExact(@PathVariable String roomNumber) {
        try {
            Optional<Room> opt = roomRepository.findByRoomNumber(roomNumber);
            return Result.success(opt.map(r -> Collections.singletonList(toView(r))).orElseGet(ArrayList::new));
        } catch (Exception e) {
            log.error("根据房间号查询失败", e);
            return Result.error("查询失败: " + e.getMessage());
        }
    }

    /** 根据状态 */
    @GetMapping("/status/{status}")
    public Result<List<RoomView>> getRoomsByStatus(@PathVariable String status) {
        try {
            Integer s = parseStatus(status);
            if (s == null) return Result.success(new ArrayList<>());
            List<RoomView> views = toViews(roomRepository.findByStatus(s));
            return Result.success(views);
        } catch (Exception e) {
            log.error("根据状态查询房间失败", e);
            return Result.error("查询失败: " + e.getMessage());
        }
    }

    /** 根据类型 */
    @GetMapping("/type/{type}")
    public Result<List<RoomView>> getRoomsByType(@PathVariable String type) {
        try {
            Integer t = parseType(type);
            if (t == null) return Result.success(new ArrayList<>());
            List<RoomView> views = toViews(roomRepository.findByRoomType(t));
            return Result.success(views);
        } catch (Exception e) {
            log.error("根据类型查询房间失败", e);
            return Result.error("查询失败: " + e.getMessage());
        }
    }

    /** 根据类型+状态 */
    @GetMapping("/type/{type}/status/{status}")
    public Result<List<RoomView>> getRoomsByTypeAndStatus(@PathVariable String type, @PathVariable String status) {
        try {
            Integer t = parseType(type);
            Integer s = parseStatus(status);
            if (t == null || s == null) return Result.success(new ArrayList<>());
            List<RoomView> views = toViews(roomRepository.findByRoomTypeAndStatus(t, s));
            return Result.success(views);
        } catch (Exception e) {
            log.error("根据类型和状态查询房间失败", e);
            return Result.error("查询失败: " + e.getMessage());
        }
    }

    /** 可用房间 */
    @GetMapping("/available")
    public Result<List<RoomView>> getAvailableRooms() {
        try {
            List<RoomView> views = toViews(roomRepository.findAvailableRooms());
            return Result.success(views);
        } catch (Exception e) {
            log.error("获取可用房间失败", e);
            return Result.error("查询失败: " + e.getMessage());
        }
    }

    /** 楼层+状态 */
    @GetMapping("/floor/{floor}/status/{status}")
    public Result<List<RoomView>> getRoomsByFloorAndStatus(@PathVariable Integer floor, @PathVariable String status) {
        try {
            Integer s = parseStatus(status);
            if (s == null) return Result.success(new ArrayList<>());
            List<RoomView> views = toViews(roomRepository.findByFloorAndStatus(floor, s));
            return Result.success(views);
        } catch (Exception e) {
            log.error("根据楼层和状态查询房间失败", e);
            return Result.error("查询失败: " + e.getMessage());
        }
    }

    /** 满员房间 */
    @GetMapping("/full")
    public Result<List<RoomView>> getFullRooms() {
        try {
            List<RoomView> views = toViews(roomRepository.findFullRooms());
            return Result.success(views);
        } catch (Exception e) {
            log.error("获取满员房间失败", e);
            return Result.error("查询失败: " + e.getMessage());
        }
    }

    /** 容量范围 */
    @GetMapping("/capacity-range")
    public Result<List<RoomView>> getRoomsByCapacityRange(@RequestParam Integer minCapacity, @RequestParam Integer maxCapacity) {
        try {
            List<RoomView> views = toViews(roomRepository.findByCapacityRange(minCapacity, maxCapacity));
            return Result.success(views);
        } catch (Exception e) {
            log.error("根据容量范围查询房间失败", e);
            return Result.error("查询失败: " + e.getMessage());
        }
    }

    /** 房间统计 */
    @GetMapping("/stats")
    public Result<Map<String, Object>> getRoomStats() {
        try {
            Map<String, Object> stats = new HashMap<>();
            int available = roomRepository.findByStatus(1).size();
            int occupied = roomRepository.findByStatus(2).size();
            int maintenance = roomRepository.findByStatus(3).size();
            int disabled = roomRepository.findByStatus(4).size();
            stats.put("available", available);
            stats.put("occupied", occupied);
            stats.put("maintenance", maintenance);
            stats.put("disabled", disabled);
            stats.put("total", available + occupied + maintenance + disabled);
            return Result.success(stats);
        } catch (Exception e) {
            log.error("获取房间统计失败", e);
            return Result.error("获取房间统计失败: " + e.getMessage());
        }
    }

    // ===== 内部辅助方法 =====
    private Integer parseType(String type) {
        if (type == null) return null;
        switch (type.trim().toUpperCase()) {
            case "SINGLE": return 1;
            case "DOUBLE": return 2;
            case "MULTIPLE": return 3; // 前端选项
            case "TRIPLE": return 3;   // 数据库枚举
            case "VIP": return 4;      // 前端选项
            case "SUITE": return 4;    // 数据库枚举
            default: return null;
        }
    }

    private Integer parseStatus(String status) {
        if (status == null) return null;
        switch (status.trim().toUpperCase()) {
            case "AVAILABLE": return 1;
            case "OCCUPIED": return 2;
            case "MAINTENANCE": return 3;
            case "RESERVED": return 4;
            case "DISABLED": return 4; // 前端使用 DISABLED
            default: return null;
        }
    }

    private List<RoomView> toViews(List<Room> rooms) {
        List<RoomView> views = new ArrayList<>();
        for (Room r : rooms) {
            views.add(toView(r));
        }
        return views;
    }

    private RoomView toView(Room r) {
        RoomView v = new RoomView();
        v.id = r.getId();
        v.roomNumber = r.getRoomNumber();
        // 类型映射到前端期望
        if (r.getRoomType() == null) {
            v.type = null;
        } else {
            switch (r.getRoomType()) {
                case 1: v.type = "SINGLE"; break;
                case 2: v.type = "DOUBLE"; break;
                case 3: v.type = "MULTIPLE"; break; // TRIPLE -> MULTIPLE
                case 4: v.type = "VIP"; break;      // SUITE -> VIP
                default: v.type = null; break;
            }
        }
        v.floor = r.getFloor();
        v.capacity = r.getCapacity();
        v.currentOccupancy = r.getCurrentOccupancy();
        // 状态映射到前端期望
        if (r.getStatus() == null) {
            v.status = null;
        } else {
            switch (r.getStatus()) {
                case 1: v.status = "AVAILABLE"; break;
                case 2: v.status = "OCCUPIED"; break;
                case 3: v.status = "MAINTENANCE"; break;
                case 4: v.status = "DISABLED"; break; // RESERVED -> DISABLED (前端文案)
                default: v.status = null; break;
            }
        }
        v.price = r.getDailyRate() == null ? null : r.getDailyRate().doubleValue();
        v.facilities = r.getFacilities();
        v.description = r.getRemarks();
        return v;
    }

    private void applyBody(Room r, Map<String, Object> body) {
        Object rn = body.get("roomNumber");
        if (rn instanceof String) r.setRoomNumber(((String) rn).trim());

        Object type = body.get("type");
        if (type instanceof String) {
            Integer t = parseType((String) type);
            if (t != null) r.setRoomType(t);
        }

        Object floor = body.get("floor");
        if (floor instanceof Number) r.setFloor(((Number) floor).intValue());

        Object capacity = body.get("capacity");
        if (capacity instanceof Number) r.setCapacity(((Number) capacity).intValue());

        Object status = body.get("status");
        if (status instanceof String) {
            Integer s = parseStatus((String) status);
            if (s != null) r.setStatus(s);
        }

        Object price = body.get("price");
        if (price instanceof Number) {
            BigDecimal bd = new BigDecimal(String.valueOf(((Number) price).doubleValue()));
            r.setDailyRate(bd);
        }

        Object facilities = body.get("facilities");
        if (facilities instanceof String) r.setFacilities((String) facilities);

        Object description = body.get("description");
        if (description instanceof String) r.setRemarks((String) description);
    }
}